/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package da;

import da.exceptions.NonexistentEntityException;
import da.exceptions.PreexistingEntityException;
import entities.Account;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import entities.Deposit;
import java.util.ArrayList;
import java.util.List;
import entities.Withdrawal;
import entities.Transfer;

/**
 *
 * @author QUY_THI
 */
public class AccountJpaController {

    public AccountJpaController() {
        emf = Persistence.createEntityManagerFactory("eBanking-ejbPU");
    }
    private EntityManagerFactory emf = null;
    
    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Account account) throws PreexistingEntityException, Exception {
        if (account.getDepositList() == null) {
            account.setDepositList(new ArrayList<Deposit>());
        }
        if (account.getWithdrawalList() == null) {
            account.setWithdrawalList(new ArrayList<Withdrawal>());
        }
        if (account.getTransferList() == null) {
            account.setTransferList(new ArrayList<Transfer>());
        }
        if (account.getTransferList1() == null) {
            account.setTransferList1(new ArrayList<Transfer>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            List<Deposit> attachedDepositList = new ArrayList<Deposit>();
            for (Deposit depositListDepositToAttach : account.getDepositList()) {
                depositListDepositToAttach = em.getReference(depositListDepositToAttach.getClass(), depositListDepositToAttach.getDepositID());
                attachedDepositList.add(depositListDepositToAttach);
            }
            account.setDepositList(attachedDepositList);
            List<Withdrawal> attachedWithdrawalList = new ArrayList<Withdrawal>();
            for (Withdrawal withdrawalListWithdrawalToAttach : account.getWithdrawalList()) {
                withdrawalListWithdrawalToAttach = em.getReference(withdrawalListWithdrawalToAttach.getClass(), withdrawalListWithdrawalToAttach.getWithdrawalID());
                attachedWithdrawalList.add(withdrawalListWithdrawalToAttach);
            }
            account.setWithdrawalList(attachedWithdrawalList);
            List<Transfer> attachedTransferList = new ArrayList<Transfer>();
            for (Transfer transferListTransferToAttach : account.getTransferList()) {
                transferListTransferToAttach = em.getReference(transferListTransferToAttach.getClass(), transferListTransferToAttach.getTransferID());
                attachedTransferList.add(transferListTransferToAttach);
            }
            account.setTransferList(attachedTransferList);
            List<Transfer> attachedTransferList1 = new ArrayList<Transfer>();
            for (Transfer transferList1TransferToAttach : account.getTransferList1()) {
                transferList1TransferToAttach = em.getReference(transferList1TransferToAttach.getClass(), transferList1TransferToAttach.getTransferID());
                attachedTransferList1.add(transferList1TransferToAttach);
            }
            account.setTransferList1(attachedTransferList1);
            em.persist(account);
            for (Deposit depositListDeposit : account.getDepositList()) {
                Account oldAccountOfDepositListDeposit = depositListDeposit.getAccount();
                depositListDeposit.setAccount(account);
                depositListDeposit = em.merge(depositListDeposit);
                if (oldAccountOfDepositListDeposit != null) {
                    oldAccountOfDepositListDeposit.getDepositList().remove(depositListDeposit);
                    oldAccountOfDepositListDeposit = em.merge(oldAccountOfDepositListDeposit);
                }
            }
            for (Withdrawal withdrawalListWithdrawal : account.getWithdrawalList()) {
                Account oldAccountOfWithdrawalListWithdrawal = withdrawalListWithdrawal.getAccount();
                withdrawalListWithdrawal.setAccount(account);
                withdrawalListWithdrawal = em.merge(withdrawalListWithdrawal);
                if (oldAccountOfWithdrawalListWithdrawal != null) {
                    oldAccountOfWithdrawalListWithdrawal.getWithdrawalList().remove(withdrawalListWithdrawal);
                    oldAccountOfWithdrawalListWithdrawal = em.merge(oldAccountOfWithdrawalListWithdrawal);
                }
            }
            for (Transfer transferListTransfer : account.getTransferList()) {
                Account oldAccountOfTransferListTransfer = transferListTransfer.getAccount();
                transferListTransfer.setAccount(account);
                transferListTransfer = em.merge(transferListTransfer);
                if (oldAccountOfTransferListTransfer != null) {
                    oldAccountOfTransferListTransfer.getTransferList().remove(transferListTransfer);
                    oldAccountOfTransferListTransfer = em.merge(oldAccountOfTransferListTransfer);
                }
            }
            for (Transfer transferList1Transfer : account.getTransferList1()) {
                Account oldAccount1OfTransferList1Transfer = transferList1Transfer.getAccount1();
                transferList1Transfer.setAccount1(account);
                transferList1Transfer = em.merge(transferList1Transfer);
                if (oldAccount1OfTransferList1Transfer != null) {
                    oldAccount1OfTransferList1Transfer.getTransferList1().remove(transferList1Transfer);
                    oldAccount1OfTransferList1Transfer = em.merge(oldAccount1OfTransferList1Transfer);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findAccount(account.getAcountCode()) != null) {
                throw new PreexistingEntityException("Account " + account + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Account account) throws NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Account persistentAccount = em.find(Account.class, account.getAcountCode());
            List<Deposit> depositListOld = persistentAccount.getDepositList();
            List<Deposit> depositListNew = account.getDepositList();
            List<Withdrawal> withdrawalListOld = persistentAccount.getWithdrawalList();
            List<Withdrawal> withdrawalListNew = account.getWithdrawalList();
            List<Transfer> transferListOld = persistentAccount.getTransferList();
            List<Transfer> transferListNew = account.getTransferList();
            List<Transfer> transferList1Old = persistentAccount.getTransferList1();
            List<Transfer> transferList1New = account.getTransferList1();
            List<Deposit> attachedDepositListNew = new ArrayList<Deposit>();
            for (Deposit depositListNewDepositToAttach : depositListNew) {
                depositListNewDepositToAttach = em.getReference(depositListNewDepositToAttach.getClass(), depositListNewDepositToAttach.getDepositID());
                attachedDepositListNew.add(depositListNewDepositToAttach);
            }
            depositListNew = attachedDepositListNew;
            account.setDepositList(depositListNew);
            List<Withdrawal> attachedWithdrawalListNew = new ArrayList<Withdrawal>();
            for (Withdrawal withdrawalListNewWithdrawalToAttach : withdrawalListNew) {
                withdrawalListNewWithdrawalToAttach = em.getReference(withdrawalListNewWithdrawalToAttach.getClass(), withdrawalListNewWithdrawalToAttach.getWithdrawalID());
                attachedWithdrawalListNew.add(withdrawalListNewWithdrawalToAttach);
            }
            withdrawalListNew = attachedWithdrawalListNew;
            account.setWithdrawalList(withdrawalListNew);
            List<Transfer> attachedTransferListNew = new ArrayList<Transfer>();
            for (Transfer transferListNewTransferToAttach : transferListNew) {
                transferListNewTransferToAttach = em.getReference(transferListNewTransferToAttach.getClass(), transferListNewTransferToAttach.getTransferID());
                attachedTransferListNew.add(transferListNewTransferToAttach);
            }
            transferListNew = attachedTransferListNew;
            account.setTransferList(transferListNew);
            List<Transfer> attachedTransferList1New = new ArrayList<Transfer>();
            for (Transfer transferList1NewTransferToAttach : transferList1New) {
                transferList1NewTransferToAttach = em.getReference(transferList1NewTransferToAttach.getClass(), transferList1NewTransferToAttach.getTransferID());
                attachedTransferList1New.add(transferList1NewTransferToAttach);
            }
            transferList1New = attachedTransferList1New;
            account.setTransferList1(transferList1New);
            account = em.merge(account);
            for (Deposit depositListOldDeposit : depositListOld) {
                if (!depositListNew.contains(depositListOldDeposit)) {
                    depositListOldDeposit.setAccount(null);
                    depositListOldDeposit = em.merge(depositListOldDeposit);
                }
            }
            for (Deposit depositListNewDeposit : depositListNew) {
                if (!depositListOld.contains(depositListNewDeposit)) {
                    Account oldAccountOfDepositListNewDeposit = depositListNewDeposit.getAccount();
                    depositListNewDeposit.setAccount(account);
                    depositListNewDeposit = em.merge(depositListNewDeposit);
                    if (oldAccountOfDepositListNewDeposit != null && !oldAccountOfDepositListNewDeposit.equals(account)) {
                        oldAccountOfDepositListNewDeposit.getDepositList().remove(depositListNewDeposit);
                        oldAccountOfDepositListNewDeposit = em.merge(oldAccountOfDepositListNewDeposit);
                    }
                }
            }
            for (Withdrawal withdrawalListOldWithdrawal : withdrawalListOld) {
                if (!withdrawalListNew.contains(withdrawalListOldWithdrawal)) {
                    withdrawalListOldWithdrawal.setAccount(null);
                    withdrawalListOldWithdrawal = em.merge(withdrawalListOldWithdrawal);
                }
            }
            for (Withdrawal withdrawalListNewWithdrawal : withdrawalListNew) {
                if (!withdrawalListOld.contains(withdrawalListNewWithdrawal)) {
                    Account oldAccountOfWithdrawalListNewWithdrawal = withdrawalListNewWithdrawal.getAccount();
                    withdrawalListNewWithdrawal.setAccount(account);
                    withdrawalListNewWithdrawal = em.merge(withdrawalListNewWithdrawal);
                    if (oldAccountOfWithdrawalListNewWithdrawal != null && !oldAccountOfWithdrawalListNewWithdrawal.equals(account)) {
                        oldAccountOfWithdrawalListNewWithdrawal.getWithdrawalList().remove(withdrawalListNewWithdrawal);
                        oldAccountOfWithdrawalListNewWithdrawal = em.merge(oldAccountOfWithdrawalListNewWithdrawal);
                    }
                }
            }
            for (Transfer transferListOldTransfer : transferListOld) {
                if (!transferListNew.contains(transferListOldTransfer)) {
                    transferListOldTransfer.setAccount(null);
                    transferListOldTransfer = em.merge(transferListOldTransfer);
                }
            }
            for (Transfer transferListNewTransfer : transferListNew) {
                if (!transferListOld.contains(transferListNewTransfer)) {
                    Account oldAccountOfTransferListNewTransfer = transferListNewTransfer.getAccount();
                    transferListNewTransfer.setAccount(account);
                    transferListNewTransfer = em.merge(transferListNewTransfer);
                    if (oldAccountOfTransferListNewTransfer != null && !oldAccountOfTransferListNewTransfer.equals(account)) {
                        oldAccountOfTransferListNewTransfer.getTransferList().remove(transferListNewTransfer);
                        oldAccountOfTransferListNewTransfer = em.merge(oldAccountOfTransferListNewTransfer);
                    }
                }
            }
            for (Transfer transferList1OldTransfer : transferList1Old) {
                if (!transferList1New.contains(transferList1OldTransfer)) {
                    transferList1OldTransfer.setAccount1(null);
                    transferList1OldTransfer = em.merge(transferList1OldTransfer);
                }
            }
            for (Transfer transferList1NewTransfer : transferList1New) {
                if (!transferList1Old.contains(transferList1NewTransfer)) {
                    Account oldAccount1OfTransferList1NewTransfer = transferList1NewTransfer.getAccount1();
                    transferList1NewTransfer.setAccount1(account);
                    transferList1NewTransfer = em.merge(transferList1NewTransfer);
                    if (oldAccount1OfTransferList1NewTransfer != null && !oldAccount1OfTransferList1NewTransfer.equals(account)) {
                        oldAccount1OfTransferList1NewTransfer.getTransferList1().remove(transferList1NewTransfer);
                        oldAccount1OfTransferList1NewTransfer = em.merge(oldAccount1OfTransferList1NewTransfer);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                String id = account.getAcountCode();
                if (findAccount(id) == null) {
                    throw new NonexistentEntityException("The account with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(String id) throws NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Account account;
            try {
                account = em.getReference(Account.class, id);
                account.getAcountCode();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The account with id " + id + " no longer exists.", enfe);
            }
            List<Deposit> depositList = account.getDepositList();
            for (Deposit depositListDeposit : depositList) {
                depositListDeposit.setAccount(null);
                depositListDeposit = em.merge(depositListDeposit);
            }
            List<Withdrawal> withdrawalList = account.getWithdrawalList();
            for (Withdrawal withdrawalListWithdrawal : withdrawalList) {
                withdrawalListWithdrawal.setAccount(null);
                withdrawalListWithdrawal = em.merge(withdrawalListWithdrawal);
            }
            List<Transfer> transferList = account.getTransferList();
            for (Transfer transferListTransfer : transferList) {
                transferListTransfer.setAccount(null);
                transferListTransfer = em.merge(transferListTransfer);
            }
            List<Transfer> transferList1 = account.getTransferList1();
            for (Transfer transferList1Transfer : transferList1) {
                transferList1Transfer.setAccount1(null);
                transferList1Transfer = em.merge(transferList1Transfer);
            }
            em.remove(account);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<Account> findAccountEntities() {
        return findAccountEntities(true, -1, -1);
    }

    public List<Account> findAccountEntities(int maxResults, int firstResult) {
        return findAccountEntities(false, maxResults, firstResult);
    }

    private List<Account> findAccountEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Account.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Account findAccount(String id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Account.class, id);
        } finally {
            em.close();
        }
    }

    public int getAccountCount() {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<Account> rt = cq.from(Account.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }

}
